package net.fruit.mq.client.internal;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/**
 * 配置加载
 * 
 * @author CNJUN
 *
 */
public class Configure {
	private static Logger log = LoggerFactory.getLogger(Configure.class);
	
	protected static String FILE_CHARSET = "UTF-8";
	
	private static Map<String, Properties> properties = new HashMap<String, Properties>();
	private static Map<String, ConfigureRead> configReads = new HashMap<String, ConfigureRead>();
	private static String[] configFileFindPath = new String[] { "WEB-INF", "WEB-INF" + File.separator + "conf", "conf", "conf" + File.separator + "conf" };
	private static ConfigureRead configRead = null;
	
	public static Properties loadConfig(String fileName) {
		String key = fileName.toUpperCase();
		
		Properties property = properties.get(key);
		if (property != null) {
			return property;
		}
		
		InputStream configStream = readFileStream(fileName);
		if (configStream != null) {
			try {
				property = new Properties();
				property.load(new InputStreamReader(configStream, FILE_CHARSET));
				properties.put(key, property);
			} catch (Exception e) {
				log.error("load config {} failure. {}.", fileName, e.getMessage());
			} finally {
				closeInputStream(configStream);
			}
		}
		
		return property;
	}
	
	public static String readFileString(String fileName, String charset) {
		String fileContent = null;
		InputStream stream = readFileStream(fileName);
		if (stream != null) {
			try {
				fileContent = IOUtils.toString(stream, charset);
			} catch (IOException e) {
				log.error("load file {}'s content failure, {}.", fileName, e.getMessage());
			} finally {
				try {
					stream.close();
				} catch (IOException e) {
				}
			}
		}
		return fileContent;
	}

	public static String readFileString(String fileName) {
		return readFileString(fileName, FILE_CHARSET);
	}

	public static JSONObject readFileToJSONObject(String fileName) {
		JSONObject jo;
		String content = readFileString(fileName);
		if (content == null) {
			jo = new JSONObject();
		} else {
			jo = JSON.parseObject(content);
		}
		return jo;
	}
	
	public static JSONArray readFileToJSONArray(String fileName) {
		JSONArray ja;
		String content = readFileString(fileName);
		if (content == null) {
			ja = new JSONArray();
		} else {
			ja = JSON.parseArray(content);
		}
		return ja;
	}
	
	public static File readFile(String fileName) {
		File file = new File(fileName);
		if (!file.exists()) {
			String configFile = PathUtil.basePath + fileName;
			file = new File(configFile);
			if (!file.exists()) {
				for (int i = 0; i < configFileFindPath.length; i++) {
					configFile = PathUtil.basePath + configFileFindPath[i] + File.separator + fileName;
					log.info("find configure file({}) {}", fileName, configFile);
					file = new File(configFile);
					if (file.exists()) {
						break;
					}
				}
			}
		}
		if (!file.exists()) {
			file = null;
		}
		return file;
	}
	
	public static URL getResource(String fileName) {
		File file = readFile(fileName);
		try {
			return file.exists() ? file.toURI().toURL() : null;
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static void closeInputStream(InputStream steam) {
		if (steam != null) {
			try {
				steam.close();
			} catch (IOException e) {
			}
		}
	}
	
	public static InputStream readFileStream(String fileName) {
		File file = readFile(fileName);
		
		InputStream configStream = null;
		
		if (file != null && file.exists()) {
			try {
				configStream = new FileInputStream(file);
			} catch (FileNotFoundException e) {
				throw new RuntimeException("Cannot find file " + fileName + ".");
			}
		} else {
			// 从classes加载
			configStream = Configure.class.getClassLoader().getParent().getResourceAsStream("/" + fileName);
			if (configStream == null) {
				configStream = Configure.class.getResourceAsStream("/" + fileName);
			}
			if (configStream == null) {
				//throw new RuntimeException("Cannot find file " + fileName + ".");
			}
		}
		
		return configStream;
	}
	
	public static void setDefaultConfig(String configName) {
		configRead = use(configName);
	}
	
	public static ConfigureRead use(String configName) {
		if (configName == null || configName.length() == 0) {
			if (configRead == null) {
				configRead = use("system.conf");
			}
			return configRead;
		}
		String key = configName.toUpperCase();
		ConfigureRead read = configReads.get(key);
		if (read == null) {
			Properties property = loadConfig(configName);
			if (property == null) {
				log.error("load config file ({}) failure.", configName);
				// throw new RuntimeException("use config file " + configName + " failure. maybe not exists.");
				read = new ConfigureRead(new Properties());
			} else {
				read = new ConfigureRead(property);
				configReads.put(key, read);
			}
		}
		return read;
	}
	
	public static ConfigureRead use() {
		return use(null);
	}
	
	public static String getString(String name, String defValue) {
		return use().getString(name, defValue);
	}
	
	public static String getString(String name) {
		return use().getString(name);
	}
	
	public static int getInt(String name, int defValue) {
		return use().getInt(name, defValue);
	}
	
	public static int getInt(String name) {
		return use().getInt(name);
	}
	
	public static float getFloat(String name, float defValue) {
		return use().getFloat(name, defValue);
	}
	
	public static float getFloat(String name) {
		return use().getFloat(name);
	}
	
	public static boolean getBoolean(String name, boolean defValue) {
		return use().getBoolean(name, defValue);
	}
	
	public static boolean getBoolean(String name) {
		return use().getBoolean(name);
	}
	
	public static String[] getStringArray(String name, String sep) {
		return use().getStringArray(name, sep);
	}
	
	public static String[] getStringArray(String name) {
		return use().getStringArray(name);
	}
	
	public static int[] getIntArray(String name, String sep) {
		return use().getIntArray(name, sep);
	}
	
	public static int[] getIntArray(String name) {
		return use().getIntArray(name);
	}
	
	public static JSONArray getJSONArray(String name) {
		return use().getJSONArray(name);
	}
	
	public static JSONObject getJSONObject(String name) {
		return use().getJSONObject(name);
	}
	
	public static class ConfigureRead {
		private Properties property;
		
		public ConfigureRead(Properties property) {
			this.property = property;
		}
		
		public Properties getProperties() {
			return this.property;
		}
		
		public Set<Object> keySet() {
		    return this.property.keySet();
		}
		
		public Set<String> stringPropertyNames() {
            return this.property.stringPropertyNames();
        }
		
		public String getString(String name, String defValue) {
			return this.property.containsKey(name) ? this.property.getProperty(name).trim() : defValue;
		}
		
		public String getString(String name) {
			return getString(name, null);
		}
		
		public int getInt(String name, int defValue) {
			String val = getString(name);
			return val == null ? defValue : Integer.parseInt(val);
		}
		
		public int getInt(String name) {
			return getInt(name, 0);
		}
		
		public float getFloat(String name, float defValue) {
			String val = getString(name);
			return val == null ? defValue : Float.parseFloat(val);
		}
		
		public float getFloat(String name) {
			return getFloat(name, 0);
		}
		
		public boolean getBoolean(String name, boolean defValue) {
			String val = getString(name);
			return val == null ? defValue : (val.equalsIgnoreCase("true") || val.equalsIgnoreCase("1")) ? true : false;
		}
		
		public boolean getBoolean(String name) {
			return getBoolean(name, false);
		}
		
		public String[] getStringArray(String name, String sep) {
			String val = getString(name);
			return val == null ? new String[0] : val.split("[" + sep + "]");
		}
		
		public String[] getStringArray(String name) {
			return getStringArray(name, ",;");
		}
		
		public int[] getIntArray(String name, String sep) {
			String arr[] = getStringArray(name, sep);
			int result[] = new int[arr.length];
			for (int i = 0; i < arr.length; i++) {
				String str = arr[i];
				if (str.length() > 0) {
					result[i] = Integer.parseInt(str);
				} else {
					result[i] = 0;
				}
			}
			return result;
		}
		
		public int[] getIntArray(String name) {
			return getIntArray(name, ",;");
		}
		
		public JSONArray getJSONArray(String name) {
			String val = getString(name);
			return val == null ? new JSONArray() : JSON.parseArray(val);
		}
		
		public JSONObject getJSONObject(String name) {
			String val = getString(name);
			return val == null ? new JSONObject() : JSON.parseObject(val);
		}
	}
}
